﻿#include "FITKSEASubSysCavity.h"
#include "FITKSEASubSysAbsShell.h"
#include "FITKAbstractSEAFace.h"
#include "FITKSEASubSysGeoProp.h"
#include "FITKAcousticsDiscModel.h"
#include "FITKAcousticsSEAModel.h"
#include "FITKAcousticsTriangles.h"
#include "FITKAcousticsDiscNodeList.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbsMaterial.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbstractSpectra.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"
#include "FITK_Component/FITK2DMeshTools/FITKAbstractRecogClosedSpace.h"
#include <QSet>


namespace Acoustics
{

    FITKSEASubSysCavity::~FITKSEASubSysCavity()
    {
        //解除face关联
        for (int shellID: _shellIDList)
        {
            this->removeShell(shellID, true);
        }
    }

    FITKAbstractSEASubSys::SEASubSysType FITKSEASubSysCavity::getSEASubSysType()
    {
        //声腔类型
        return FITKAbstractSEASubSys::SEASubSysType::SEACavity;
    }

    void FITKSEASubSysCavity::appendShell(const int shellID)
    {
        //已经包含则不操作，避免重复追加
        if (_shellIDList.contains(shellID)) return;
       
        //face追加
        FITKAbstractSEASubSysShell* shell = FITKDATAREPO->getTDataByID<FITKAbstractSEASubSysShell>(shellID);
        if (shell == nullptr) return;
        _shellIDList.append(shellID);
        FITKAbstractSEAFace* face = shell->getFaceObj();
        if (!face ) return;
        _faceIDList.append(face->getDataObjectID());
        //记录关联
        face->addConnector(this);
    }

    void FITKSEASubSysCavity::removeShell(const int shellID, const bool& removeFace)
    {
        //移除
        _shellIDList.removeAll(shellID);
        if (!removeFace) return;
        FITKAbstractSEASubSysShell* shell = FITKDATAREPO->getTDataByID<FITKAbstractSEASubSysShell>(shellID);
        if (shell == nullptr) return;
        FITKAbstractSEAFace* face = shell->getFaceObj();

        if (!face) return;
        //remove face
        _faceIDList.removeAll(face->getDataObjectID());
        face->removeConnector(this);
    }

    int FITKSEASubSysCavity::getShellCount() const
    {
        return _shellIDList.count();
    }

    int FITKSEASubSysCavity::getShellID(const int index)
    {
        //越界返回-1
        if (index < 0 || index >= _shellIDList.size()) return -1;
        return _shellIDList.at(index);
    }

    FITKAbstractSEASubSysShell* FITKSEASubSysCavity::getShell(const int index)
    {
        const int id = this->getShellID(index);
        if (id <= 0) return nullptr;
        //从数据仓库查找
        return FITKDATAREPO->getTDataByID<FITKAbstractSEASubSysShell>(id);
    }


    int FITKSEASubSysCavity::getShellIndex(const int id)
    {
        return _shellIDList.indexOf(id);
    }

    void FITKSEASubSysCavity::removeFace(const int faceID)
    {
        FITKAbstractSEAFace* face = FITKDATAREPO->getTDataByID<FITKAbstractSEAFace>(faceID);
        if (!face) return;
        //remove face
        _faceIDList.removeAll(faceID);
        face->removeConnector(this);
    }

    int FITKSEASubSysCavity::getFaceCount() const
    {
        return _faceIDList.size();
    }


    int FITKSEASubSysCavity::getFaceID(const int index) const
    {
        if (index < 0 || index >= _faceIDList.size()) return -1;
        return _faceIDList.at(index);
    }

    Acoustics::FITKAbstractSEAFace* FITKSEASubSysCavity::getFace(const int index) const
    {
        //face ID
        const int id = this->getFaceID(index);
        //获取对象
        return FITKDATAREPO->getTDataByID<FITKAbstractSEAFace>(id);
    }

    void FITKSEASubSysCavity::addFace(const int faceID)
    {
        //获取face
        FITKAbstractSEAFace* face = FITKDATAREPO->getTDataByID<FITKAbstractSEAFace>(faceID);
        if (face == nullptr) return;
        //获取face对应的shell
        FITKAbstractSEASubSys* s = face->getAConnectedShellSubSys();
        if (s == nullptr) return;
        //追加shell
        this->appendShell(s->getDataObjectID());
    }

    QList<int> FITKSEASubSysCavity::getNodeIDs() const
    {
        QSet <int> ids;
        //遍历全部face
        const int nface = this->getFaceCount();
        for (int i =0;i< nface; ++i)
        {
            FITKAbstractSEAFace* face = this->getFace(i);
            if(face == nullptr) continue;
            FITKAcousticsTriangles* tris = face->getTriangleMesh();
            if(tris == nullptr) continue;
            //面上的全部节点ID
            QList<int> fids = tris->getAllNodeIDs();

            ids.unite(fids.toSet());
        }
        return ids.toList();
    }

    bool FITKSEASubSysCavity::isContainsNode(const int id) const
    {
        //遍历全部face
        const int nface = this->getFaceCount();
        for (int i = 0; i < nface; ++i)
        {
            FITKAbstractSEAFace* face = this->getFace(i);
            if (!face) continue;
            //有一个面包含则认为声腔包含节点
            if (face->isContainsNode(id)) return true;
        }
        //所有的Face都不包含
        return false;
    }

    void FITKSEASubSysCavity::setVolume(int volume)
    {
        _v_a_p[0] = volume;
    }

    void FITKSEASubSysCavity::setSurfaceArea(int surfaceArea)
    {
        _v_a_p[1] = surfaceArea;
    }

    void FITKSEASubSysCavity::setPerimeter(int perimeter)
    {
        _v_a_p[2] = perimeter;
    }

    bool FITKSEASubSysCavity::isOverride(int type)
    {
        switch (type)
        {
        case 1:
        case 2:
        case 3:
            return !(_v_a_p[type - 1] < 0);
        default:
            break;
        }
        return false;
    }

    double FITKSEASubSysCavity::getVolume()
    {
        if (_v_a_p[0] < 0)
            return _geoProp->getGeoProp(FITKSEASubSysGeoProp::GeoPropType::Volume);
        return _v_a_p[0];
    }

    double FITKSEASubSysCavity::getSurfaceArea()
    {
        if (_v_a_p[1] < 0)
            return _geoProp->getGeoProp(FITKSEASubSysGeoProp::GeoPropType::Area);
        return _v_a_p[1];
    }

    double FITKSEASubSysCavity::getPerimeter()
    {
        if (_v_a_p[2] < 0)
            return _geoProp->getGeoProp(FITKSEASubSysGeoProp::GeoPropType::Circumference);
        return _v_a_p[2];
    }

    void FITKSEASubSysCavity::setDampingID(int id)
    {
        if (id < 0)
        {
            //设置噪音控制处理的吸收类型
            _dampingID = id;
            return;
        }
        //设置频谱
        FITKAcousticsAbstractSpectra* spectra = FITKDATAREPO->getTDataByID<FITKAcousticsAbstractSpectra>(id);
        if (!spectra)return;
        FITKAcousticsAbstractSpectra::AcousticsSpectraType type = spectra->getSpectraType();
        if (!(type == FITKAcousticsAbstractSpectra::AcousticsSpectraType::Damping || type == FITKAcousticsAbstractSpectra::AcousticsSpectraType::Absorption))
            return;
        _dampingID = id;
    }

    int FITKSEASubSysCavity::getDampingID()
    {
        return _dampingID;
    }

    FITKAcousticsAbstractSpectra* FITKSEASubSysCavity::getDampingSpectra()
    {
        if (_dampingID < 0)return nullptr;
        return FITKDATAREPO->getTDataByID<FITKAcousticsAbstractSpectra>(_dampingID);
    }

    int FITKSEASubSysCavity::getDampingType()
    {
        //使用噪音控制处理的吸收类型
        if (_dampingID < 0) return -1;
        //频谱类型
        FITKAcousticsAbstractSpectra* spectra = this->getDampingSpectra();
        if (!spectra) return 0;
        return spectra->getSpectraType();
    }

    void FITKSEASubSysCavity::setModalDensity(int ID)
    {
        _modalDensity = ID;
    }

    int FITKSEASubSysCavity::getModalDensity()
    {
        return _modalDensity;
    }

    void FITKSEASubSysCavity::setInSEAMatrixSolution(bool is)
    {
        _inSEAMatrixSolution = is;
    }

    bool FITKSEASubSysCavity::getInSEAMatrixSolution()
    {
        return _inSEAMatrixSolution;
    }

    bool FITKSEASubSysCavity::updateCoordinate()
    {
        //声腔无局部坐标系，直接跳过
        return true;
    }

    bool FITKSEASubSysCavity::isEnclosedSpace()
    {
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel)return false;
        //获取节点管理器
        Acoustics::FITKAcousticsDiscNodeList* discNodesList = discModel->getNodes();
        if (!discNodesList)return false;

        //存储点和单元
        QList<Core::FITKNode*> nodeList;
        QList<Interface::FITKElementTri3*> eleList;
        
        //获取点数据
        QList<int> nodes = this->getNodeIDs();
        for (int id : nodes)
        {
            Core::FITKNode* nodeData = discNodesList->getNodeByID(id);
            if (!nodeData)continue;
            nodeList.append(nodeData);
        }
        //获取单元
        int count = this->getFaceCount();
        for (int i = 0; i < count; ++i)
        {
            FITKAbstractSEAFace*  faceData = this->getFace(i);
            if (!faceData)continue;
            FITKAcousticsTriangles* triMesh = faceData->getTriangleMesh();
            if (!triMesh)continue;
            //获取单元
            int eleNum = triMesh->getElementCount();
            for (int i = 0; i < eleNum; ++i)
            {
                Interface::FITKElementTri3* ele = dynamic_cast<Interface::FITKElementTri3*>(triMesh->getElementAt(i));
                if (!ele) continue;
                eleList.append(ele);
            }
        }
        if (nodeList.isEmpty() || eleList.isEmpty()) return false;
        //计算封闭空间
        Interface::FITKAbstractRecogClosedSpace * space = Interface::FITKAbstractRecogClosedSpace::createFITKRecogClosedSpace();
        if (!space->initMesh(nodeList, eleList)) return false;
        space->meshPreProcess();
        space->recogClosedSpace(true);
        QList<QList<int>> elemIndexList = space->getFacesIndex();
        QList<double> volume = space->getSpaceVolume();
        delete space;
        if (elemIndexList.size() == 1 && elemIndexList.at(0).size() == eleList.size() && volume.size() == 1)
        {
            if (_geoProp) _geoProp->setGeoProp(FITKSEASubSysGeoProp::GeoPropType::Volume, volume.at(0));
            return true;
        }
        return false;
    }

}


